// Copyright 2013 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package dfa.axis.v1_19.matchtables;

import com.google.api.ads.dfa.axis.factory.DfaServices;
import com.google.api.ads.dfa.axis.v1_19.ApiException;
import com.google.api.ads.dfa.axis.v1_19.DfaSite;
import com.google.api.ads.dfa.axis.v1_19.DfaSiteRecordSet;
import com.google.api.ads.dfa.axis.v1_19.DfaSiteSearchCriteria;
import com.google.api.ads.dfa.axis.v1_19.Site;
import com.google.api.ads.dfa.axis.v1_19.SiteRecordSet;
import com.google.api.ads.dfa.axis.v1_19.SiteRemote;
import com.google.api.ads.dfa.axis.v1_19.SiteSearchCriteria;
import com.google.api.ads.dfa.lib.client.DfaSession;

import java.rmi.RemoteException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Implementation of LookupObject that will generate Site/SD Site match table. Extends
 * AbstractSimpleLookupObject to handle aggregation of Site IDs.
 * 
 * @author Moshe Kahan
 */
class SiteLookup extends AbstractSimpleLookupObject {

  private SiteRemote siteService;
  private TableSettings tableSettings;

  /**
   * Constructor accepts DFA service/session objects needed to create SOAP remotes to the
   * API.
   *
   * @param dfaServices DFA services object needed to create SOAP remotes to the API
   * @param session DFA session object needed to create SOAP remotes to the API
   * @param tableSettings match table application configuration used as a MatchTable object factory
   */
  SiteLookup(DfaServices dfaServices, DfaSession session, TableSettings tableSettings) {
    // Request the advertiser service from the service client factory.
    super(LookupField.SiteId.getFieldName());
    siteService = dfaServices.get(session, SiteRemote.class);
    this.tableSettings = tableSettings;
  }

  /**
   * Called when parsing/aggregation is complete. Will lookup via SOAP all unique DFA entries
   * in the DT file and pass data to MatchTable class.
   *
   * @param outputPath location of match table to be generated.
   */
  public void generateMatchTable(String outputPath)
      throws MatchTableFileException, DfaRemoteException {
    MatchTable siteMatchTable = tableSettings.createMatchTable(MatchTable.Type.SITE);
    if (siteMatchTable != null) {
      siteMatchTable.open(outputPath);
      siteMatchTable.printProgress();
    }

    Set<DfaSite> dfaSiteSet = new HashSet<DfaSite>();
    Map<Long, String> siteDirectoryIdMap = new HashMap<Long, String>();

    // Retrieve all DFA Sites.
    SoapPageableLookup<DfaSite, DfaSiteSearchCriteria> dfaSiteSoapLookup =
        new SoapPageableLookup<DfaSite, DfaSiteSearchCriteria>(entityIds,
            new DfaSiteSoapLookupCallback());
    while (dfaSiteSoapLookup.hasNext()) {
      DfaSite result = dfaSiteSoapLookup.next();
      dfaSiteSet.add(result);
      if (result.getSiteDirectorySiteId() > 0) {
        siteDirectoryIdMap.put(result.getSiteDirectorySiteId(), null);
      }
    }

    if (!dfaSiteSet.isEmpty()) {
      // Retrieve all SD Site info associated with the DFA Sites.
      SoapPageableLookup<Site, SiteSearchCriteria> soapLookupSdSite =
          new SoapPageableLookup<Site, SiteSearchCriteria>(siteDirectoryIdMap.keySet(),
              new SdSiteSoapLookupCallback());
      while (soapLookupSdSite.hasNext()) {
        Site result = soapLookupSdSite.next();
        siteDirectoryIdMap.put(result.getId(), result.getName());
      }

      // Generate rows for all DFA Sites.
      for (DfaSite dfaSite : dfaSiteSet) {
        siteMatchTable.write(
            Long.toString(dfaSite.getId()),
            dfaSite.getName(),
            Long.toString(dfaSite.getSiteDirectorySiteId()),
            siteDirectoryIdMap.get(dfaSite.getSiteDirectorySiteId()));
      }
    }
    if (siteMatchTable != null) {
      siteMatchTable.close();
    }
  }

  // SoapLookupCallbacks

  private class DfaSiteSoapLookupCallback implements
    SoapPageableLookupCallback<DfaSite, DfaSiteSearchCriteria> {

    public int getRecords(DfaSiteSearchCriteria criteria, List<DfaSite> recordList)
        throws ApiException, RemoteException {
      DfaSiteRecordSet records = siteService.getDfaSites(criteria);
      int pages = records.getTotalNumberOfPages();
      for (DfaSite record : records.getRecords()) {
        recordList.add(record);
      }
      return pages;
    }

    public DfaSiteSearchCriteria getCriteria() {
      return new DfaSiteSearchCriteria();
    }
  }

  private class SdSiteSoapLookupCallback implements
    SoapPageableLookupCallback<Site, SiteSearchCriteria> {

    public int getRecords(SiteSearchCriteria criteria, List<Site> recordList)
        throws ApiException, RemoteException {
      SiteRecordSet records = siteService.getSitesByCriteria(criteria);
      int pages = records.getTotalNumberOfPages();
      for (Site record : records.getRecords()) {
        recordList.add(record);
      }
      return pages;
    }

    public SiteSearchCriteria getCriteria() {
      return new SiteSearchCriteria();
    }
  }
}
